
import { MsgPlayerInpFrame } from "../shared/gameClient/protocols/MsgPlayerInpFrame";
import { MatchRequestServer } from "../shared/matchRequest/MatchRequestServer";
import { logger } from "../shared/tsgf/logger";
import { EMatchFromType } from "../shared/tsgf/match/Models";
import { IPlayerInfo } from "../shared/tsgf/player/IPlayerInfo";
import { IResult, Result } from "../shared/tsgf/Result";
import { EPlayerInputFrameType } from "../shared/tsgf/room/IGameFrame";
import { EFrameSyncState, IRoomInfo } from "../shared/tsgf/room/IRoomInfo";
import { arrRemoveItems } from "../shared/tsgf/Utils";
import { IPlayer } from "../shared/tsgfServer/auth/Models";
import { IRoomGameServerRegInfo } from "../shared/tsgfServer/room/Models";
import { RoomHelper } from "../shared/tsgfServer/room/RoomHelper";
import { ConnectionCollection } from "./ConnectionCollection";
import { FrameSyncGame } from "./FrameSyncGame";
import { GameConnMgr } from "./GameConnMgr";
import { ClientConnection, GameServer, GameWsServer } from "./GameServer";
import { Rooms } from "./GameServerAppRoomMgr";


/**游戏房间操作对象*/
export class GameRoom {
    private gameWsServer: GameWsServer;
    private gameConnMgr: GameConnMgr;
    private matchReqServer: MatchRequestServer;
    public onlinePlayerConns: ConnectionCollection;
    public roomRegInfo: IRoomGameServerRegInfo;
    public roomInfo: IRoomInfo;
    public game: FrameSyncGame;
    public isDismiss: boolean = false;

    /**招人匹配请求id,如果开启了则有值*/
    private joinUsMatchReqId?: string;

    constructor(roomRegInfo: IRoomGameServerRegInfo, roomInfo: IRoomInfo,
        gameWsServer: GameWsServer, gameConnMgr: GameConnMgr, matchReqServer: MatchRequestServer) {
        this.roomRegInfo = roomRegInfo;
        this.roomInfo = roomInfo;
        this.gameConnMgr = gameConnMgr;
        this.gameWsServer = gameWsServer;
        this.matchReqServer = matchReqServer;
        this.game = new FrameSyncGame(this.roomInfo, gameWsServer, this.gameConnMgr);
        this.onlinePlayerConns = new ConnectionCollection(c => c.playerId);
    }
    public dispose() {

        //如果还没解散就释放,则先执行解散
        if (!this.isDismiss) {
            //执行实际的解散逻辑（数据操作）
            this.internalDismissRoom();
            //触发事件
            this.triggerDismissRoomNotify(this.roomInfo.playerList);
        }

        this.game.dispose();

        this.onlinePlayerConns.clearAllConnections();
    }

    /**触发玩家进入房间事件的通知,需要在连接加入到本房间在线数组前调用*/
    protected async triggerPlayerJoinRoomNotify(joinPlayerInfo: IPlayerInfo) {
        await this.gameWsServer.broadcastMsg('NotifyJoinRoom', {
            joinPlayerId: joinPlayerInfo.playerId,
            roomInfo: this.roomInfo,
        }, this.onlinePlayerConns.connections);
    }
    /**触发玩家离开房间事件的通知, 需要在玩家连接移除后调用*/
    protected async triggerPlayerLeaveRoomNotify(leavePlayerInfo: IPlayerInfo) {
        await this.gameWsServer.broadcastMsg('NotifyLeaveRoom', {
            leavePlayerInfo: leavePlayerInfo,
            roomInfo: this.roomInfo,
        }, this.onlinePlayerConns.connections);
    }
    protected async triggerDismissRoomNotify(playerInfos: IPlayerInfo[]) {
        let connList: ClientConnection[] = [];
        for (let playerInfo of playerInfos) {
            let playerConn = this.gameConnMgr.getPlayerConn(playerInfo.playerId);
            if (!playerConn) continue;
            connList.push(playerConn);
        }
        await this.gameWsServer.broadcastMsg('NotifyDismissRoom', {
            roomInfo: this.roomInfo,
        }, connList);
    }
    protected async triggerStartFrameSyncNotify(startPlayerInfo: IPlayerInfo) {
        await this.gameWsServer.broadcastMsg('NotifyStartFrameSync', {
            startPlayerId: startPlayerInfo.playerId,
            roomInfo: this.roomInfo,
        }, this.onlinePlayerConns.connections);
    }
    protected async triggerStopFrameSyncNotify(stopPlayerInfo: IPlayerInfo) {
        await this.gameWsServer.broadcastMsg('NotifyStopFrameSync', {
            stopPlayerId: stopPlayerInfo.playerId,
            roomInfo: this.roomInfo,
        }, this.onlinePlayerConns.connections);
    }
    public async triggerChangePlayerNetworkState(playerInfo: IPlayerInfo) {
        await this.gameWsServer.broadcastMsg('NotifyChangePlayerNetworkState', {
            roomInfo: this.roomInfo,
            changePlayerId: playerInfo.playerId,
            networkState: playerInfo.networkState,
        }, this.onlinePlayerConns.connections);
    }

    protected async autoSetRoomJoinUsMatch(): Promise<void> {

        if (this.roomInfo.isPrivate
            || this.roomInfo.isForbidJoin
            || !this.roomInfo.matcherKey
            || this.roomInfo.maxPlayers <= this.roomInfo.playerList.length) {
            //这里应该关闭匹配
            this.disabledRoomJoinUsMatch();
        } else {
            //这里应该启用招人匹配
            //已经开启则忽略
            if (this.joinUsMatchReqId) return;
            //请求匹配,并记录请求id
            let ret = await this.matchReqServer.requestMatch(this.roomRegInfo.appId, {
                matchFromType: EMatchFromType.RoomJoinUs,
                matchFromInfo: {
                    roomId: this.roomInfo.roomId,
                },
                matcherKey: this.roomInfo.matcherKey,
                maxPlayers: this.roomInfo.maxPlayers,
                matcherParams: {},
            });
            if (!ret.succ) {
                logger.error(`GameRoom.enabledRoomJoinUsMatch.requestMatch失败:${ret.err}  roomInfo:`, this.roomInfo);
                return;
            }
            this.joinUsMatchReqId = ret.data;
        }
    }
    protected async disabledRoomJoinUsMatch(): Promise<void> {
        if (this.joinUsMatchReqId) {
            await this.matchReqServer.cancelMatch(this.roomRegInfo.appId, this.joinUsMatchReqId);
            this.joinUsMatchReqId = undefined;
        }
    }

    /**
     * [实际的数据操作] 解散房间
     * @date 2022/5/11 - 14:36:49
     *
     * @protected
     * @async
     * @returns {Promise<void>}
     */
    protected async internalDismissRoom(): Promise<void> {
        if (this.isDismiss) return;

        //停止游戏
        this.game.stopGame();

        //删除房间注册信息, 截断后续新加入的人
        await RoomHelper.deleteRoomRegInfo(this.roomInfo.roomId);

        for (let playerInfo of this.roomInfo.playerList) {
            let roomPlayer = this.gameConnMgr.getPlayer(playerInfo.playerId);
            if (!roomPlayer) continue;
            await this.internalLeaveRoom(roomPlayer);
        }
        this.isDismiss = true;

        //如果有开启招人匹配则停止
        await this.disabledRoomJoinUsMatch();
    }
    /**
     * [实际的数据操作] 玩家离开房间
     * @date 2022/5/10 - 22:43:36
     *
     * @public
     * @async
     * @param {IPlayer} player
     * @returns {Promise<void>}
     */
    protected async internalLeaveRoom(player: IPlayer): Promise<void> {
        //当前房间id设置为未定义
        player.currRoomId = undefined;
        //移除房间的玩家列表中该玩家对象
        arrRemoveItems(this.roomInfo.playerList, p => p.playerId === player.playerInfo.playerId);
        //移除房间在线玩家连接
        this.onlinePlayerConns.removeConnection(player.playerInfo.playerId);

        //同步信息给房间注册信息
        this.roomRegInfo.currPlayerIds = this.roomInfo.playerList.map(p => p.playerId);
        RoomHelper.updateRoomRegInfoFromLeavePlayer(this.roomRegInfo, player.playerInfo.playerId);


        //最后再加一个玩家输入帧
        this.game.playerInpFrame(player, EPlayerInputFrameType.LeaveRoom, inpFrame => inpFrame.playerInfo = player.playerInfo);

        //根据当前房间情况去自动开启或关闭招人匹配
        await this.autoSetRoomJoinUsMatch();
    }


    /**
     * 玩家加入房间，会根据房间等的规则判断是否可以加入
     * @date 2022/5/10 - 22:43:36
     *
     * @public
     * @async
     * @param {IPlayer} player
     * @returns {Promise<IResult<IRoomInfo>>}
     */
    public async joinRoom(player: IPlayer): Promise<IResult<IRoomInfo>> {
        let existsPlayerInfo = this.roomInfo.playerList.find(p => p.playerId === player.playerInfo.playerId);
        if (existsPlayerInfo) {
            //这个玩家已经在房间中了，直接成功！
            return Result.buildSucc(this.roomInfo);
        }
        if (this.roomInfo.isForbidJoin && this.roomInfo.ownerPlayerId !== player.playerInfo.playerId) {
            //不可加入时，只有房主可以加入
            return Result.buildErr('房间不可加入！', 1002);
        }
        if (this.roomInfo.playerList.length >= this.roomInfo.maxPlayers) {
            return Result.buildErr('房间人数已满！', 1001);
        }

        let playerConn = this.gameConnMgr.getPlayerConn(player.playerInfo.playerId);
        if (!playerConn) {
            return Result.buildErr('玩家不在线！', 5001);
        }

        //数据加入
        player.currRoomId = this.roomInfo.roomId;
        this.roomInfo.playerList.push(player.playerInfo);

        //触发事件
        await this.triggerPlayerJoinRoomNotify(player.playerInfo);
        this.onlinePlayerConns.addConnection(playerConn);

        //通知房间注册信息
        this.roomRegInfo.currPlayerIds = this.roomInfo.playerList.map(p => p.playerId);
        RoomHelper.updateRoomRegInfoFromJoinPlayer(this.roomRegInfo, player.playerInfo.playerId);

        //加玩家加入房间的特殊输入帧
        this.game.playerInpFrame(player, EPlayerInputFrameType.JoinRoom, inpFrame => inpFrame.playerInfo = player.playerInfo);

        //根据当前房间情况去自动开启或关闭招人匹配
        await this.autoSetRoomJoinUsMatch();

        return Result.buildSucc(this.roomInfo);
    }


    /**
     * 离开玩家当前所在的房间,如果离开后没人了,房间将被解散，返回房间是否被解散
     * @date 2022/5/10 - 22:43:36
     *
     * @public
     * @async
     * @param {IPlayer} player
     * @returns {Promise<IResult<IRoomInfo>>}
     */
    public async leaveRoom(player: IPlayer): Promise<IResult<IRoomInfo>> {
        await this.internalLeaveRoom(player);

        if (this.roomInfo.playerList.length <= 0) {
            //房间没人了，直接解散
            await this.internalDismissRoom();
        } else {
            //还有人，才需要触发事件
            await this.triggerPlayerLeaveRoomNotify(player.playerInfo);
        }

        return Result.buildSucc(this.roomInfo);
    }


    /**
     * 解散房间
     * @date 2022/5/11 - 14:27:55
     *
     * @public
     * @async
     * @param {IPlayer} player 当前玩家
     * @returns {Promise<IResult<IRoomInfo>>}
     */
    public async dismissRoom(player: IPlayer): Promise<IResult<IRoomInfo>> {
        if (this.roomInfo.ownerPlayerId !== player.playerInfo.playerId) {
            return Result.buildErr('只有房主才可以解散房间！');
        }

        //拷贝一份原有的玩家信息列表(排除自己)，用于做事件通知
        let notifyPlayerInfos = this.roomInfo.playerList.filter(p => p.playerId !== player.playerInfo.playerId);

        //执行实际的解散逻辑（数据操作）
        await this.internalDismissRoom();

        //触发事件
        this.triggerDismissRoomNotify(notifyPlayerInfos);

        return Result.buildSucc(this.roomInfo);
    }



    /**
     * 开始游戏帧同步
     * @date 2022/5/16 - 16:44:34
     *
     * @public
     */
    public async startGameFrameSync(player: IPlayer): Promise<void> {
        this.roomInfo.startGameTime = Date.now();
        this.roomInfo.frameSyncState = EFrameSyncState.START;
        //await等通知消息都发了,再启动游戏的帧同步
        await this.triggerStartFrameSyncNotify(player.playerInfo);
        this.game.startGame();
    }

    /**
     * 停止游戏帧同步
     * @date 2022/5/16 - 16:45:58
     *
     * @public
     */
    public async stopGameFrameSync(player: IPlayer): Promise<void> {
        this.game.stopGame();
        this.roomInfo.frameSyncState = EFrameSyncState.STOP;
        await this.triggerStopFrameSyncNotify(player.playerInfo);
    }



}